#!/bin/env ruby

begin
	require 'rubygems'
rescue
	LoadError
end

require 'gtk2'
#:nodoc: 
include Gtk
require './Observable.rb'
require './Inventaire.rb'
require './Case.rb'

##
#=Classe Interface
#La classe Interface gère l'interface utilisateur du Jeu.
#=Variables d'instance :
#[@listeObservateurs] Tableau des Observateurs
#[@etats] Tableau des etats
#[@listeLabel] Liste des labels de l'Interface
#[@listeBoutons] Liste des boutons de l'Interface
#[@carte] Tableau des Case à afficher
#[@objetSelectionne] L'objet ayant le "focus"
#[@couleurArrierePlan] couleur d'arrière-plan
#[@cheminImgArrierePlan] Image d'arrière-plan
class Interface
	#:nodoc: 
	include Observable	

	# Méthode new privatisée
	private_class_method :new
	
	# Méthode de classe permettant la création d'instance d'Interface remplacant le new
	def Interface.creer
		new()
	end
	
	# Méthode d'initialisation de l'Interface
	def initialize
		#Initialisation des variables d'instance
		@listeObservateurs	= Array.new
		@etats			= Array.new
		#pour la couleur du texte
		@listeLabel		= Array.new
		#pour les raccourcis boutons
		@listeBoutons		= Array.new
		@carte			= Array.new( Array.new())
		@objetSelectionne	= nil
		
		@couleurArrierePlan	= Gdk::Color.parse('#272743')
		@cheminImgArrierePlan	= "./images/arriere_plan.png"
		@couleurTexte		= Gdk::Color.parse('white')
		
		@bSon			= false
		
		@dialog			= nil
		
		initBoutons()
		initRaccourcis()
		initLabels()
		
		#Initialisation de la langue de l'interface par défaut
		setLangue($langue)
		#Création de la fenètre de l'application
		@application = Window.new("Legend of Ouf")
		@application.set_size_request(1152,864)
		@application.set_resizable(false)
		@application.signal_connect('destroy'){ main_quit }
		#ajout d'un container à la fenètre qui contiendra tout
		@application.add(window = VBox.new(true, 5))
		
		setBackground(@couleurArrierePlan)
		style = RcStyle.new()
		style.set_bg_pixmap_name(STATE_NORMAL,"./images/arriere_plan.png")
		@application.modify_style(style)
		setFenetreDeDemarrage()
		
		#affiche tout
		@application.show_all
		
	end #fin initialize
	
	# Création de tous les boutons avec leurs images et leurs handlers, retourne la liste des boutons
	def initBoutons()
		#Crée un bouton, l'ajoute à la liste, le met sans relief et le retourne
		def creerBouton()
			bouton = Button.new()
			bouton.set_relief(	RELIEF_NONE)
			@listeBoutons.push(	bouton)
			return bouton
		end
		
		#Création des boutons
		# menu départ
		@boutonNouvellePartie	= creerBouton()
		@boutonChargerPartie	= creerBouton()
		@boutonOptionsPartie	= creerBouton()
		@boutonQuitterPartie	= creerBouton()
		# menu jeu
		@boutonSauvegarder	= creerBouton()
		@boutonCharger		= creerBouton()
		@boutonInventaire	= creerBouton()
		@boutonScore		= creerBouton()
		@boutonOptions		= creerBouton()
		@boutonAide		= creerBouton()
		@boutonQuitter		= creerBouton()
		# menu action
		@boutonPasser		= creerBouton()
		@boutonSoigner		= creerBouton()
		@boutonRamasser		= creerBouton()
		# menu déplacement
		@boutonHaut		= creerBouton()
		@boutonBas		= creerBouton()
		@boutonGauche		= creerBouton()
		@boutonDroit		= creerBouton()
		# inventaire
		@boutonUtiliser		= creerBouton()
		@boutonJeter		= creerBouton()
		@boutonRetourCarte	= creerBouton()
		# game over
		@boutonRetourMenu	= creerBouton()
		# fenetre difficulte
		@boutonFacile		= creerBouton()
		@boutonMoyen		= creerBouton()
		@boutonDifficile	= creerBouton()
		# fenetre option
		@boutonFrancais		= creerBouton()
		@boutonAnglais		= creerBouton()
		@boutonRaccourcis	= creerBouton()
		
		@boutonAppliquer	= creerBouton()
		@boutonAnnuler		= creerBouton()
		
		#Handler des boutons
		@boutonNouvellePartie.signal_connect('clicked'){onClickNouvellePartie }
		@boutonChargerPartie.signal_connect('clicked'){	onClickCharger }
		@boutonOptionsPartie.signal_connect('clicked'){	onClickOptions }
		@boutonQuitterPartie.signal_connect('clicked'){	onClickQuitter }
		
		@boutonSauvegarder.signal_connect('clicked'){	onClickSauvegarder }
		@boutonCharger.signal_connect('clicked'){	onClickCharger }
		@boutonInventaire.signal_connect('clicked'){	onClickInventaire }
		@boutonScore.signal_connect('clicked'){		onClickScore }
		@boutonOptions.signal_connect('clicked'){	onClickOptions }
		@boutonAide.signal_connect('clicked'){		onClickAide }
		@boutonQuitter.signal_connect('clicked'){	onClickQuitter }
		
		@boutonPasser.signal_connect('clicked'){	onClickPasser }
		@boutonRamasser.signal_connect('clicked'){	onClickRamasser }
		@boutonSoigner.signal_connect('clicked'){	onClickSoigner }
		
		@boutonHaut.signal_connect('clicked'){		onClickHaut }
		@boutonBas.signal_connect('clicked'){		onClickBas }
		@boutonGauche.signal_connect('clicked'){	onClickGauche }
		@boutonDroit.signal_connect('clicked'){		onClickDroit }
		
		@boutonUtiliser.signal_connect('clicked'){	onClickUtiliser }
		@boutonJeter.signal_connect('clicked'){		onClickJeter }
		@boutonRetourCarte.signal_connect('clicked'){	montrerCarte(@carte) }
		
		@boutonRetourMenu.signal_connect('clicked'){	
			setBackground(@couleurArrierePlan)
			style = RcStyle.new()
			style.set_bg_pixmap_name(STATE_NORMAL,"./images/arriere_plan.png")
			@application.modify_style(style)
			setFenetreDeDemarrage
		}
		@boutonFacile.signal_connect('clicked'){
			@dialog.hide
			setFenetreDeJeu
			@etats[0] = "nouvelle partie"
			@etats[1] = "Facile"
			notifierObservateurs()
		}
		@boutonMoyen.signal_connect('clicked'){	
			@dialog.hide
			setFenetreDeJeu
			@etats[0] = "nouvelle partie"
			@etats[1] = "Moyen"
			notifierObservateurs()
		}
		@boutonDifficile.signal_connect('clicked'){
			@dialog.hide
			setFenetreDeJeu
			@etats[0] = "nouvelle partie"
			@etats[1] = "Difficile"
			notifierObservateurs()
		}		
		# fenetre option
		@boutonFrancais.signal_connect('clicked'){
			@etats[0] = "langue"
			@etats[1] = "fr"
		}
		@boutonAnglais.signal_connect('clicked'){
			@etats[0] = "langue"
			@etats[1] = "en"
		}
		@boutonRaccourcis.signal_connect('clicked'){	
			onClickRaccourcis
		}
		
		@boutonAnnuler.signal_connect('clicked'){	
			@dialog.response(Dialog::RESPONSE_CANCEL)
		}
		@boutonAppliquer.signal_connect('clicked'){	
			@dialog.response(Dialog::RESPONSE_ACCEPT)
		}
		#Met implicitement les images des boutons en fonctions de la langue
		setLangue($langue)
		
		return @listeBoutons
	end
	
	#Création des raccourcis par défaut, retourne une Gtk::ListStore(String, Gdk::Pixbuf, String, Widget)
	def initRaccourcis()
		#Initialisation des raccourcis
		@indexStock	= 0
		@indexPixbuf	= 1
		@indexRaccourcis= 2
		@indexBouton	= 3
		
		@listeRaccourcis = ListStore.new(String, Gdk::Pixbuf, String, Widget)
		
		#Ajoute un raccourci à un bouton donné pour une touche donné, retourne un Gtk::Iter, nouvelle ligne de la liste de raccourcis
		#- +bouton+ : le bouton sur lequel on ajouter un raccourci
		#- +touche+ : la touche associé soit un Gdk::Keyval
		def ajouterRaccourciBouton(bouton, touche)
			raccourcis					= @listeRaccourcis.insert(@listeBoutons.index(bouton))
			raccourcis[@indexBouton]	= bouton
			raccourcis[@indexRaccourcis]= "#{Gdk::Keyval.to_name(touche)}"
			
			return 
		end
		
		ajouterRaccourciBouton(@boutonInventaire,	Gdk::Keyval::GDK_i)
		ajouterRaccourciBouton(@boutonScore,		Gdk::Keyval::GDK_t)
		ajouterRaccourciBouton(@boutonOptions,		Gdk::Keyval::GDK_o)
		ajouterRaccourciBouton(@boutonAide,		Gdk::Keyval::GDK_a)
		
		ajouterRaccourciBouton(@boutonRamasser,		Gdk::Keyval::GDK_r)
		ajouterRaccourciBouton(@boutonSoigner,		Gdk::Keyval::GDK_s)
		ajouterRaccourciBouton(@boutonPasser,		Gdk::Keyval::GDK_p)
		
		ajouterRaccourciBouton(@boutonHaut,		Gdk::Keyval::GDK_Up)
		ajouterRaccourciBouton(@boutonBas,		Gdk::Keyval::GDK_Down)
		ajouterRaccourciBouton(@boutonGauche,		Gdk::Keyval::GDK_Left)
		ajouterRaccourciBouton(@boutonDroit,		Gdk::Keyval::GDK_Right)
		
		return @listeRaccourcis
	end
	
	#Création des différents labels par défaut, retourne la liste des labels
	def initLabels()
		#Créer un label en l'ajoutant à la liste, retourne le label
		#- +texte+ : la chaîne à afficher
		def creerLabel(texte)
			label = Label.new(texte)
			@listeLabel.push(label)
			return label
		end
		@labelEnergie	= creerLabel("0")
		@labelOr	= creerLabel("0")
		@labelForce	= creerLabel("0")
		@labelDefense	= creerLabel("0")
		@labelScore	= creerLabel("0")
		
		return @listeLabel
	end	


  #Change la langue de l'Interface pour cele passée en paramètre, retourne la nouvelle valeur de langue
	def setLangue(langue)
		$langue = langue
		
		#IMAGES
		cheminBoutons = "./images/boutons/"+langue+"/"
		
		@boutonNouvellePartie.set_image(Image.new(	cheminBoutons+"bouton_nouvelle_partie.png"))
		@boutonChargerPartie.set_image(	Image.new(	cheminBoutons+"bouton_charger_partie.png"))
		@boutonOptionsPartie.set_image(	Image.new(	cheminBoutons+"bouton_options_partie.png"))
		@boutonQuitterPartie.set_image(	Image.new(	cheminBoutons+"bouton_quitter_partie.png"))
		
		@boutonSauvegarder.set_image(	Image.new(	cheminBoutons+"bouton_sauvegarder.png"))
		@boutonCharger.set_image(	Image.new(	cheminBoutons+"bouton_charger.png"))
		@boutonInventaire.set_image(	Image.new(	cheminBoutons+"bouton_inventaire.png"))
		@boutonScore.set_image(		Image.new(	cheminBoutons+"bouton_score.png"))
		@boutonOptions.set_image(	Image.new(	cheminBoutons+"bouton_options.png"))
		@boutonAide.set_image(		Image.new(	cheminBoutons+"bouton_aide.png"))
		@boutonQuitter.set_image(	Image.new(	cheminBoutons+"bouton_quitter.png"))
		
		@boutonPasser.set_image(	Image.new(	cheminBoutons+"bouton_passer.png"))
		@boutonSoigner.set_image(	Image.new(	cheminBoutons+"bouton_guerisseur.png"))
		@boutonRamasser.set_image(	Image.new(	cheminBoutons+"bouton_ramasser.png"))
	
		@boutonUtiliser.set_image(	Image.new(	cheminBoutons+"bouton_inventaire_utiliser.png"))
		@boutonJeter.set_image(		Image.new(	cheminBoutons+"bouton_inventaire_detruire.png"))
		@boutonRetourCarte.set_image(	Image.new(	cheminBoutons+"bouton_retour.png"))
		
		#image " > " IconSize::BUTTON
		#image " -> " IconSize::LARGE_TOOLBAR
		@boutonHaut.set_image(		Image.new(Stock::GO_UP, IconSize::LARGE_TOOLBAR))
		@boutonBas.set_image(		Image.new(Stock::GO_DOWN, IconSize::LARGE_TOOLBAR))
		@boutonGauche.set_image(	Image.new(Stock::GO_BACK, IconSize::LARGE_TOOLBAR))
		@boutonDroit.set_image(		Image.new(Stock::GO_FORWARD, IconSize::LARGE_TOOLBAR))
		
		@boutonRetourMenu.set_image(	Image.new(	cheminBoutons+"bouton_retour.png"))
		
		@boutonFacile.set_image(	Image.new(	cheminBoutons+"difficulte_facile.png"))
		@boutonMoyen.set_image(		Image.new(	cheminBoutons+"difficulte_moyen.png"))
		@boutonDifficile.set_image(	Image.new(	cheminBoutons+"difficulte_difficile.png"))
		
		@boutonFrancais.set_image(	Image.new(	cheminBoutons+"bouton_francais.png"))
		@boutonAnglais.set_image(	Image.new(	cheminBoutons+"bouton_anglais.png"))
		@boutonRaccourcis.set_image(	Image.new(	cheminBoutons+"bouton_modifier.png"))
		
		@boutonAppliquer.set_image(	Image.new(	cheminBoutons+"bouton_ok.png"))
		@boutonAnnuler.set_image(	Image.new(	cheminBoutons+"bouton_retour.png"))
		
		#Chemin Fichiers
		@cheminManuel		= "./langue/"+langue+"/README"
		
		@etats[0]="langue"
		@etats[1]=langue
		notifierObservateurs()
		
		return langue
	end
	
	#Met en marche le son d'arrière plan
	#- +bool+ : Vrai pour mettre le son en marche ou Faux pour l'éteindre
	#FIXME pas de moyen simple, multiplateforme ruby trouvé
	def setSon(bool)
		file	= "./music.mp3"
	end


  #Actualisation des statistiques 
  #- +heros+ : le Heros dont on affiche les caractéristiques
	def actualiseStat(heros)
		actualiseEnergie(heros.getEnergie())
		actualiseOr(heros.getOrPossede())
		actualiseForce(heros.getForce())
		actualiseDefense(heros.getDefense())
		
		return self
	end
	
  #Actualise la valeur d'énergie, retourne la nouvelle quantité d'énergie
  #- +quantiteEnergie+ : le modificateur d'énergie appliqué
	def actualiseEnergie(quantiteEnergie)
		if(@labelEnergie != nil)
			@labelEnergie.text = quantiteEnergie.to_s
		end
		
		return quantiteEnergie
	end
	

  #Actualise la quantité d'or, retourne la nouvelle quantité d'or
   #- +quantiteOr+ : le modificateur d'or appliqué
	def actualiseOr(quantiteOr)
		if(@labelOr != nil)
			@labelOr.text = quantiteOr.to_s
		end
		
		return quantiteOr
	end
	
  #Actualise la valeur de force, retourne la nouvelle valeur de force
  #- +quantiteForce+ : le modificateur de force appliqué
	def actualiseForce(quantiteForce)
		if(@labelForce != nil)
			@labelForce.text = quantiteForce.to_s
		end
		
		return quantiteForce
	end
	
#Actualise la valeur de défense, retourne la nouvelle valeur de défense
 #- +quantiteDefense+ : le modificateur de défense appliqué
	def actualiseDefense(quantiteDefense)
		if(@labelDefense != nil)
			@labelDefense.text = quantiteDefense.to_s
		end
		
		return quantiteDefense
	end
	
#Actualise le score total du Heros, retourne le score
 #- +scoreTotal+ : la valeur du score du joueur
	def actualiseScore(scoreTotal)
		if(@labelScore != nil)
			@labelScore.text = scoreTotal.to_s
		end
		
		return scoreTotal
	end
	
  #Affecte une couleur au texte de l'Interface, retourne la couleur Gdk::Color
   #- +couleur+ : la couleur à appliquer
	def setForeground(couleur)		
		#l'interface contient une liste de tous les labels
		#pour chaque label on change sa couleur
		@listeLabel.each{ |label|
			if(label != nil)
				label.modify_fg(STATE_NORMAL, couleur)
			end
		}
		
		@couleurTexte = couleur
		
		return @couleurTexte
	end
	
  #Affecte une couleur passée en paramètre à l'arrière-plan de l'Interface, retourne la couleur Gdk::Color
     #- +couleur+ : la couleur à appliquer
	def setBackground(couleur)
		@couleurArrierePlan = couleur
		
		@application.modify_bg(STATE_NORMAL, @couleurArrierePlan)
		
		return @couleurArrierePlan
	end
	
  #Affecte une image (chemin en paramètre) à l'arrière-plan, retourne le style RcStyle de la fenêtre
	def setBackgroundImage(cheminImage)
		setBackground(@couleurArrierePlan)
		style = RcStyle.new()
		style.set_bg_pixmap_name(STATE_NORMAL,cheminImage)
		@application.modify_style(style)
		
		@cheminImgArrierePlan = cheminImage
		return style
	end
	

   #Affiche la fenêtre de démarrage, retourne un Gtk::Window
	def setFenetreDeDemarrage()
		@application.children.each{ |child|
			@application.remove(child)
		}
		window = HBox.new(false,nil)
		
		#pack_start colle la VBox(packerV) vers la gauche
		window.pack_start(packerV = VBox.new(false, 5), false, false, 0)
		
		#pack_end colle les boutons vers le bas
		#ajout d'un bouton permettant de quitter l'appli
		@boutonQuitterPartie.removeFromParent
		packerV.pack_end(@boutonQuitterPartie, false, false, 0)
		#ajout d'un bouton permettant de choisir les options
		@boutonOptionsPartie.removeFromParent
		packerV.pack_end(@boutonOptionsPartie, false, false, 0)
		#ajout d'un bouton permettant de charger une partie existante
		@boutonChargerPartie.removeFromParent
		packerV.pack_end(@boutonChargerPartie, false, false, 0)
		#ajout d'un bouton permettant de créer une nouvelle partie
		@boutonNouvellePartie.removeFromParent
		packerV.pack_end(@boutonNouvellePartie, false, false, 0)
		
		setForeground(@couleurTexte)
		
		@application.add(window)
		@application.show_all
		
		return @application
	end
	
	#Affiche la fenetre de jeu, retourne un Gtk::Window 
	def setFenetreDeJeu()
		@application.children.each{ |child|
			@application.remove(child)
		}
		
		window = VBox.new(false, 5)
		@idHandlerRaccourci = @application.signal_connect("key-press-event") do |w, e|
			nomCle = Gdk::Keyval.to_name(e.keyval)
			@listeRaccourcis.each{ |model,path,iter|
				raccourci	= @listeRaccourcis.get_value(iter,@indexRaccourcis)
				bouton		= @listeRaccourcis.get_value(iter,@indexBouton)

				if nomCle == raccourci && bouton.visible?
					bouton.clicked
				end
			}
		end
		
		#				Menu Jeu
		#-----------------------------------
		#ajout du menu jeu compacté en haut du jeu
		#les widgets du menu de jeu sont tous de même taille
		window.pack_start((menuJeu = HBox.new(true,0)), false, false, 0)
		
		#placement des boutons
		@boutonSauvegarder.removeFromParent
		@boutonCharger.removeFromParent
		@boutonInventaire.removeFromParent
		@boutonScore.removeFromParent
		@boutonOptions.removeFromParent
		@boutonAide.removeFromParent
		@boutonQuitter.removeFromParent
		menuJeu.add( @boutonSauvegarder )
		menuJeu.add( @boutonCharger )
		menuJeu.add( @boutonInventaire )
		menuJeu.add( @boutonScore )
		menuJeu.add( @boutonOptions )
		menuJeu.add( @boutonAide )
		menuJeu.add( @boutonQuitter )
		
		#ajoute un séparateur entre le menu de jeu et le reste du jeu
		window.pack_start(HSeparator.new, false, false, 0)
		
		#ajout d'un container qui contiendra tout sauf le menu du jeu, 
		#et qui prend tout l'espace restant de la fenetre
		window.add(contenuHbox = HBox.new(false, 5))
		
		#				Menu Action
		#-----------------------------------
		#ajout du menu action compacté à gauche
		#les widgets du menu ne seront pas tous forcement de la même taille,
		#et l'espace entre eux des de 2 pixels
		contenuHbox.pack_start((menuAction = VBox.new(false,2))	, false, false, 5)
	
		#ajoute des élements au menu d'action 
		menuAction.pack_start(tableRessources = Table.new(5,2)	, false, false, 0)
		@boutonPasser.removeFromParent
		@boutonSoigner.removeFromParent
		@boutonRamasser.removeFromParent
		#ajout d'un container, qui contiendra les touches directionnels
		menuAction.pack_start(HSeparator.new()				, false, false, 0)
		menuAction.pack_start((menuDeplacement = Table.new(3,3,true))	, false, false, 0)
		menuAction.pack_start(HSeparator.new()				, false, false, 0)
		menuAction.pack_start(@boutonPasser				, false, false, 0)
		menuAction.pack_start(@boutonSoigner				, false, false, 0)
		menuAction.pack_start(@boutonRamasser				, false, false, 0)
		
		#ajout dans une Table l'affichage de l'energie, de l'or,
		#de la force et de la defense dont dispose le joueur
		#ajout des images
		tableRessources.attach_defaults(Image.new("./images/energie.png")	,0,1,0,1)
		tableRessources.attach_defaults(Image.new("./images/or.png")		,0,1,1,2)
		tableRessources.attach_defaults(Image.new("./images/force.png")		,0,1,2,3)
		tableRessources.attach_defaults(Image.new("./images/defense.png")	,0,1,3,4)
		tableRessources.attach_defaults(Image.new("./images/score.png")		,0,1,4,5)
		
		#ajout des valeurs
		@labelEnergie.removeFromParent
		@labelOr.removeFromParent
		@labelForce.removeFromParent
		@labelDefense.removeFromParent
		@labelScore.removeFromParent
		tableRessources.attach_defaults(@labelEnergie	,1,2,0,1)
		tableRessources.attach_defaults(@labelOr	,1,2,1,2)
		tableRessources.attach_defaults(@labelForce	,1,2,2,3)
		tableRessources.attach_defaults(@labelDefense	,1,2,3,4)
		tableRessources.attach_defaults(@labelScore	,1,2,4,5)
		
		#				Menu Deplacement
		#-----------------------------------
		
		@boutonHaut.removeFromParent
		@boutonBas.removeFromParent
		@boutonGauche.removeFromParent
		@boutonDroit.removeFromParent
		
		#placement des boutons de déplacement dans la table
		menuDeplacement.attach_defaults(@boutonHaut,1,2,0,1)
		menuDeplacement.attach_defaults(@boutonBas,1,2,2,3)
		menuDeplacement.attach_defaults(@boutonGauche,0,1,1,2)
		menuDeplacement.attach_defaults(@boutonDroit,2,3,1,2)
		
		#ajout d'un séparateur verticale entre le menu d'action et la carte et le log.
		contenuHbox.pack_start(VSeparator.new, false, false, 0)
		
		#				Carte
		#-----------------------------------
		
		#ajout d'un container, qui contiendra la carte et le log occupant tous l'espace restant de la fenetre
		contenuHbox.add(contenuEtLogVBox = VBox.new)
		#ajout d'un drawing area qui contiendra la carte
		contenuEtLogVBox.pack_start(@contenuJeu = VBox.new(false,nil), false, false, 5)
		@contenuJeu.add(drawingHBox = HBox.new)
		drawingHBox.pack_start(@drawingArea = DrawingArea.new, false, false, 0)
		
		#				Log
		#-----------------------------------
		
		#frame contenant le log
		contenuEtLogVBox.add(@frameLog = Frame.new())
		
		#ajout du log à la frame du log
		@frameLog.add(boxLog = ScrolledWindow.new(nil,nil))
			boxLog.add_with_viewport(@log = TextView.new())
			@log.buffer.text	= $ref[$langue => "debutPartie"].to_s
			boxLog.set_height_request(160)
		
		@log.set_left_margin(20)
		@log.set_right_margin(20)
		#background et foreground du text
		@log.modify_base(STATE_NORMAL, @couleurArrierePlan)
		@log.modify_text(STATE_NORMAL, @couleurTexte)
		
		setForeground(@couleurTexte)
		
		@application.add(window)
		@application.show_all
		
		return @application
	end
	
	#Affiche la fenêtre de Game Over
	#- +score+ : un Score, le score final à afficher, retourne un Gtk::Window où est représentée la fenêtre
	def setFenetreGameOver(score)

		@application.children.each{ |child|
			@application.remove(child)
		}

		window = VBox.new(false, 5)
		window.add(vbox = VBox.new(true))
			vbox.add(HBox.new())
			vbox.add(hbox = HBox.new(true))
				hbox.add(creerTableauScore(score))
				# vide à droite
				hbox.add(HBox.new())
			@frameLog.removeFromParent
			
			#affichage des crédits
			credits = VBox.new(true,0)
			credits.add(Label.new(""))
			titre = creerLabel($ref[$langue => "credits"])
			titre.modify_font(Pango::FontDescription.new('Arial 14'))
			titre.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(titre)
			piou = creerLabel($ref[$langue => "piou"])
			piou.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(piou)
			pierreAlexandre = creerLabel($ref[$langue => "pierreAlexandre"])
			pierreAlexandre.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(pierreAlexandre)
			dardy = creerLabel($ref[$langue => "dardy"])
			dardy.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(dardy)
			charles = creerLabel($ref[$langue => "charles"])
			charles.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(charles)
			jerome = creerLabel($ref[$langue => "jerome"])
			jerome.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(jerome)
			sandrine = creerLabel($ref[$langue => "sandrine"])
			sandrine.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(sandrine)
			nathan = creerLabel($ref[$langue => "nathan"])
			nathan.modify_fg(STATE_NORMAL, @couleurTexte)
			credits.add(nathan)
			credits.add(Label.new(""))
			vbox.add(credits);
			
			vbox.add(@frameLog)
		if(@idHandlerRaccourci != nil)
			@application.signal_handler_disconnect(@idHandlerRaccourci)
			@idHandlerRaccourci = nil
		end
		
		#Bouton pour retourner au menu
		@boutonRetourMenu.removeFromParent
		window.pack_end(@boutonRetourMenu	, false, false, 0)
		
		setBackground(@couleurArrierePlan)
		style = RcStyle.new()
		style.set_bg_pixmap_name(STATE_NORMAL,"./images/game_over.png")
		@application.modify_style(style)
		
		@application.add(window)
		@application.show_all

		return @application
	end
	
#Implementation du module observable
#========================================================================

	#Ajoute un observateur de l'interface, retourne la liste des observateurs
	#- +observateur+ : Un observateur à ajouter
	def ajouterObservateur(observateur)
		@listeObservateurs.push(observateur)
		
		return @listeObservateurs
	end
	
	#Supprime un observateur de l'Interface, retourne la liste des observateurs
	#- +observateur+ : Un observateur à supprimer
	def supprimerObservateur(observateur)
		@listeObservateurs.delete(observateur)
		
		return @listeObservateurs
	end
	
	#Notifie au observateur un changement d'etat, retourne la liste des observateurs
	def notifierObservateurs()
		@listeObservateurs.each{ |observateur|
			observateur.actualiser(self)
		}
			
		return @listeObservateurs
	end
	
	#Méthode permettant la récupération des etats de l'interface observable, retourne un tableau représentant le dernier état de l'Interface
	def getEtats()
		return @etats
	end
	
	#Méthode qui permet d'ajouter du text en début de log, retourne le texte ajouté
	#- +texte+ : Le texte à ajouter dans le log
	#- +:textTag+ : Le format du texte, si aucun paramètre n'est passé, c'est un texte non formaté
	def miseAJourLog(texte, textTag = TextTag.new())
		buffer = @log.buffer
		buffer.tag_table().add(textTag)
		buffer.insert(buffer.start_iter, texte.to_s+"\n",textTag)
	
		return texte
	end
	
	#Méthode qui force l'affichage de la file d'événement
	def forcerAffichage()
		#Force l'affichage
		while (Gtk.events_pending?)
			Gtk.main_iteration
		end
	end

#Méthode qui change le contenu de la fenetre,
#équivalent au contenu dans une page html
#========================================================================
																
	#Méthode qui actualise le contenu de la carte en la reconstruisant graphiquement en totalité, retourne le container du contenu
	#- +carte+ : Une matrice bidimentionnelle de Case
	def montrerCarte(carte)
		effacerContenu()
		
		#drawing hbox permet de packer la boite pour effacer le blanc autour
		@contenuJeu.add(drawingHBox = HBox.new)
		drawingHBox.pack_start(@drawingArea = DrawingArea.new, false, false, 0)
		
		#la carte est un liste de ligne, elle meme des listes des cases
		nbLigne = carte.length
		nbColonne = carte[0].length
		
		tailleCase = 880/nbColonne
		@largeur_case = tailleCase
		@hauteur_case = tailleCase
			
		@drawingArea.set_size_request(nbColonne*@largeur_case, nbLigne*@hauteur_case)
		@drawingArea.modify_bg(STATE_NORMAL, Gdk::Color.parse('black'))
		
		#Chargement de fichier donc création de pixbuf lourd,
		#=> on charge que les terrains ce qui faire 6 pixbuf au lieu de 150 pour un case 15*10
		chemins = Hash.new()
		$terrains.each{ |terrain|
			chemins.merge!( terrain => Gdk::Pixbuf.new("./images/terrain/"+terrain+".png",@largeur_case,@hauteur_case) )
		}
		
		#Récupère le chemin de l'image à afficher par dessus le fond de la case passée en paramètre, retourne le chemin de l'image, nil si introuvable
		#- +case+ : La case qui sera étudiée
		def getCheminImagePrioritaire(c)
			#priorité Heros > PNJ > Objet
			chemin = "./images/"
			if( ! c.obstacle?()) 
				herosPresent	= (c.getHeros() != nil)
				pnjPresent	= (c.getPnj() != nil)
				objetsPresent	= ( c.getObjets().length > 0)
				orPresent	= (c.getOr() != nil && c.getOr() > 0)
				if(herosPresent)
					return chemin+"heros.png"
				elsif(pnjPresent)
					return chemin+c.getPnj().getId()+".png"
				elsif(objetsPresent)
					return chemin+"urne_bleue.png"
				elsif(orPresent)
					return chemin+"urne.png"
				end
			end
	
			return nil
		end
		
		@drawingArea.signal_connect("expose_event") do
			colonne = ligne = 0
			carte.each{ |rangee|
				rangee.each{ |uneCase|
				#affiche l'arrière plan de la case
					cheminForegroundCase = nil
					if(uneCase.visible?())
						imageBg = chemins[uneCase.obtenirTypeTerrain()]
						if(imageBg != nil)
							@drawingArea.window.draw_pixbuf(
								@drawingArea.style.fg_gc(@drawingArea.state),
								imageBg,
								0, 0,
								colonne, ligne,
								-1, -1,
								Gdk::RGB::DITHER_NORMAL, 0, 0)
						end
				
						cheminForegroundCase = getCheminImagePrioritaire(uneCase)
						if(cheminForegroundCase != nil)
							imageFg = Gdk::Pixbuf.new(cheminForegroundCase,@largeur_case,@hauteur_case)
							@drawingArea.window.draw_pixbuf(
								@drawingArea.style.fg_gc(@drawingArea.state),
								imageFg,
								0, 0,
								colonne, ligne,
								-1, -1,
								Gdk::RGB::DITHER_NORMAL, 0, 0)
						end
					end
					
					colonne += @largeur_case
					#affiche l'élement visible dessus( héros, ennemi, nourriture, or )
			 	}
				ligne += @hauteur_case
				colonne = 0
			}
		end
		
		@carte = carte
		
		@contenuJeu.show_all
		sleep(0.05)
		return @contenuJeu
	end
	
	#Affiche l'inventaire passer en paramètre dans le contenu du jeu, retourne le container du contenu
	#- +inventaire+ : Un Inventaire qui sera affiché
	def montrerInventaire(inventaire)
		effacerContenu()
		
		listeObjets		= inventaire.getListeElt()
		listeEquipements	= inventaire.getListeEqt()
		
		nbObjets		= listeObjets.length
		nbEquipements		= listeEquipements.length
		
		maxObjets		= inventaire.getNbEmplacementElt()
		maxEquipements		= inventaire.getNbEmplacementEqt()
		
		@contenuJeu.add(inventaireUI = VBox.new(false,nil))
			inventaireUI.add(	itemsObjets = Table.new(maxObjets/10,10))
			inventaireUI.add(	HSeparator.new() )
			inventaireUI.add(	itemsEquipements = HBox.new(false,nil))
			inventaireUI.add(	HSeparator.new() )
			inventaireUI.add(	boutonsHBox = HBox.new(false,nil))
			
		
		dossier	= "./images/items/"
		#remplissage itemsObjets
		x=0
		y=0
		#liste bouton pour faire signal_connect sinon connect tous relié au dernier bouton(meme reference)
		listeBoutonObjet = Array.new
		
		wItem = 50
		hItem = 60
		for index in 0..maxObjets-1
			objet = listeObjets[index]
			widget = nil
			if index < nbObjets
				widget = Button.new()
				widget.set_image(Image.new(dossier+objet.getId()+".png"))
				listeBoutonObjet.push([widget,index])
			else
				widget = Image.new(dossier+"bouton_item_empty.png")
			end
			widget.set_size_request(wItem,hItem)
			itemsObjets.attach_defaults(widget, x, x+1, y, y+1)
			x += 1
			if(x > 10)
				y += 1
				x = 0
			end
		end
		
		@objetSelectionne = nil
		listeBoutonObjet.each{ |bouton,indexObjet|
			bouton.set_relief( RELIEF_NONE)
			objet = listeObjets[indexObjet]
			bouton.set_tooltip_markup(objet.to_s)
			bouton.signal_connect("clicked"){
				@objetSelectionne = listeObjets[indexObjet]
				@boutonUtiliser.set_sensitive(true)
				@boutonJeter.set_sensitive(true)
			}
		}
		
		#liste bouton pour faire signal_connect sinon connect tous relié au dernier bouton(meme reference)
		listeBoutonEqt = Array.new
		
		for index in 0..maxEquipements-1
			equipement = listeEquipements[index]
			widget = nil
			if equipement != nil
				widget	= Button.new()
				path	= dossier+equipement.getId()+".png"
				widget.set_image(Image.new(path))
				listeBoutonEqt.push([widget,index])
			else
				# note key = maHash.key(value) n'existe pas avant ruby 1.9.3
				nom = nil
				$indexType.each{ |key,value|
					if(value == index)
						nom = key
					end
				}
				if(nom != nil)
					path	= dossier+nom+"_none.png"	
				else
					path	= dossier+"bouton_item_empty.png"
				end
				widget	= Image.new(path)
			end
			widget.set_size_request(wItem,hItem)
			itemsEquipements.add(widget)
			x += 1
			if(x > 10)
				y += 1
				x = 0
			end
		end
		
		listeBoutonEqt.each{ |bouton,indexEquipement|
			bouton.set_relief( RELIEF_NONE)
			equipement = listeEquipements[indexEquipement]
			bouton.set_tooltip_markup(equipement.to_s)
			bouton.signal_connect("clicked"){
				@objetSelectionne = listeEquipements[indexEquipement]
				@boutonUtiliser.set_sensitive(false)
				@boutonJeter.set_sensitive(false)
			}
		}
		
		boutonsHBox.add(		hboxUtiliser = HBox.new())
			@boutonUtiliser.removeFromParent
			hboxUtiliser.pack_end(	@boutonUtiliser, false, false, 0)
		boutonsHBox.add(		hboxJeter = HBox.new())
			@boutonJeter.removeFromParent
			hboxJeter.pack_start(	@boutonJeter, false, false, 0)
		boutonsHBox.add(		hboxRetour = HBox.new())
			@boutonRetourCarte.removeFromParent
			hboxRetour.pack_start(	@boutonRetourCarte, false, false, 0)
			
		@boutonUtiliser.set_sensitive(false)
		@boutonJeter.set_sensitive(false)
		
		inventaireUI.show_all
		
		@contenuJeu.show_all
		return @contenuJeu
	end
	
	#Affiche le score passé en paramètre dans le contenu du jeu, retourne le container du contenu
	#- +score+ : Un score que l'on souhaite montrer
	def montrerScore(score)
		effacerContenu()
		
		@contenuJeu.add(	vbox = VBox.new())
			vbox.add(	creerTableauScore(score))
			vbox.add( packerH = HBox.new())
			@boutonRetourCarte.removeFromParent
			packerH.pack_start(@boutonRetourCarte, false, false, 0)
		
		@contenuJeu.show_all
		return @contenuJeu
	end
	
	#Affiche le combat entre le heros et le personnage passer en paramètre, retourne le container du contenu
	#- +heros+ : Un Heros qui se bat
	#- +personnage+ : Un Ennemi qui se bat
	def montrerCombat(heros, personnage)
		effacerContenu()
		
		taille	= 400
		largeur	= taille
		hauteur	= taille
		
		#drawing hbox permet de packer la boite pour effacer le blanc autour
		@contenuJeu.add(drawingHBox = HBox.new)
		drawingHBox.pack_start(@drawingArea = DrawingArea.new, false, false, 0)
			
		@drawingArea.set_size_request(largeur,hauteur)
		@drawingArea.modify_bg(STATE_NORMAL, Gdk::Color.parse('white'))
				
		cheminHeros	= "./images/heros.png"
		cheminPerso	= "./images/"+personnage.getId()+".png"
		cheminTerrain	= "./images/terrain/"+heros.getCase().obtenirTypeTerrain()+".png"
		
		taille		= 80
		largeurElt	= taille
		hauteurElt	= taille
		
		imgHeros	= Gdk::Pixbuf.new(cheminHeros,largeurElt,hauteurElt)
		imgPerso	= Gdk::Pixbuf.new(cheminPerso,largeurElt,hauteurElt)
		imgTerrain	= Gdk::Pixbuf.new(cheminTerrain,largeur,hauteur)
		
		gc		= @drawingArea.style.fg_gc(@drawingArea.state)
		
		@drawingArea.signal_connect("expose_event") do
			@drawingArea.window.draw_pixbuf(
					gc,
					imgTerrain,
					0, 0,
					0, 0,
					-1, -1,
					Gdk::RGB::DITHER_NORMAL, 0, 0)
			
			@drawingArea.window.draw_pixbuf(
					gc,
					imgPerso,
					0, 0,
					largeur-largeurElt, hauteur/2-hauteurElt/2,
					-1, -1,
					Gdk::RGB::DITHER_NORMAL, 0, 0)
					
			@drawingArea.window.draw_pixbuf(
					gc,
					imgHeros,
					0, 0,
					0, hauteur/2-hauteurElt/2,
					-1, -1,
					Gdk::RGB::DITHER_NORMAL, 0, 0)
		end

		@contenuJeu.show_all
		
		#Force l'affichage
		forcerAffichage()
		sleep(0.5)
		
		return @contenuJeu
	end
	
	#Actualise les boutons visibles du menu d'actions en fonction de la case passée en paramètre, retourne le container du menu d'actions
	#- +case+ : la Case dont on étudie le contenu
	def actualiseMenuAction(caseActuelle)
		if(caseActuelle.presentObjet?() || caseActuelle.getOr() > 0)
			@boutonRamasser.show
		else
			@boutonRamasser.hide
		end
		
		pnj = caseActuelle.getPnj()
		if( pnj != nil && pnj.class == Guerisseur)
			@boutonSoigner.show
		else
			@boutonSoigner.hide
		end
		
		return @boutonRamasser.parent
	end
	

#========================================================================
#Méthode PRIVEES
#========================================================================
private
	
	#Efface le contenu de la fenetre de jeu (equivalent au content sur une page html)
	#
	#Return le container représentant le contenu 
	def effacerContenu()
		@contenuJeu.children.each{ |child|
			@contenuJeu.remove(child)
		}
		return @contenuJeu
	end
	
	#Créer un tableau de score
	#- +score+ : Un score que l'on souhaite maitre dans un tableau
	#
	#Return le tableau des scores
	def creerTableauScore(score)
		#Score
		scoreUI = HBox.new()
		scoreUI.add( labelsNoms = VBox.new())
		scoreUI.add( labelsQuantites = VBox.new())
		
		# Noms
		labelsNoms.add(label = Label.new($ref[$langue => "nbMonstres"]))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsNoms.add(label = Label.new($ref[$langue => "nbOr"]))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsNoms.add(label = Label.new($ref[$langue => "nbDeplacements"]))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsNoms.add(label = Label.new($ref[$langue => "nbNourriture"]))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsNoms.add(HSeparator.new())
		
		# Valeurs associées
		labelsNoms.add(label = Label.new($ref[$langue => "scoreTotal"]))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsQuantites.add(label = Label.new(score.getNbMonstreCombattus().to_s))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsQuantites.add(label = Label.new(score.getNbOr().to_s))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsQuantites.add(label = Label.new(score.getNbDeplacementEffectue().to_s))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsQuantites.add(label = Label.new(score.getNbNourritureUtilisee().to_s))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		labelsQuantites.add(HSeparator.new())
		
		labelsQuantites.add(label = Label.new(score.calculScore().to_s))
		label.modify_fg(STATE_NORMAL, @couleurTexte)
		
		scoreUI.set_height_request(150)
		return scoreUI
	end

#Méthodes réalisées par les HANDLER
#========================================================================
	
	#Action réaliser lors de clic sur un bouton nouvelle partie, demande la difficulté
	def onClickNouvellePartie
		dialog = Dialog.new($ref[$langue => "choixDiff"],
				   @application,
				    Dialog::DESTROY_WITH_PARENT)
		
		dialog.vbox.add(table = Table.new(4,5,true))
		
		# dessus vide
		table.attach_defaults(HBox.new(), 	0, 5, 0, 2)
		# gauche vide
		table.attach_defaults(HBox.new(), 	0, 1, 2, 4)
		# droite vide
		table.attach_defaults(HBox.new(), 	4, 5, 2, 4)
		
		@boutonFacile.removeFromParent
		table.attach_defaults(@boutonFacile, 	1, 2, 2, 3)
		@boutonMoyen.removeFromParent
		table.attach_defaults(@boutonMoyen, 	2, 3, 2, 3)
		@boutonDifficile.removeFromParent
		table.attach_defaults(@boutonDifficile, 3, 4, 2, 3)
		@boutonAnnuler.removeFromParent
		table.attach_defaults(@boutonAnnuler,	2, 3, 3, 4)

		chemin = "./images/boutons/"+$langue+"/difficulte_fond.png"
		
		style = RcStyle.new()
		style.set_bg_pixmap_name(STATE_NORMAL,chemin)
		dialog.modify_style(style)	
		
		dialog.set_size_request(738,344)
		dialog.set_resizable(false)
		dialog.show_all
		dialog.signal_connect("delete-event"){
			dialog.hide
		}
		
		@dialog	= dialog
		reponse = dialog.run
		if(reponse == Dialog::RESPONSE_CANCEL)
			dialog.hide
		end
		
		return @application
	end
	
	#Action réaliser lors de clic sur un bouton de sauvegarde, affiche une boite de dialogue pour que l'utilisateur choisisse d'écraser une sauvegarde ou d'en créer une autre
	def onClickSauvegarder
		@dialogSauvegarder = Dialog.new($ref[$langue => "sauvegarder"],
				    	@application,
				    	Dialog::DESTROY_WITH_PARENT
				 	)
				 	
		@cheminFichierSauvegarde = "./sauvegarde/"
	#Methode qui permet de se rappeler recursivement lorsque l'on clic sur annuler.
		#niveau 1 =clic=> niveau 2, niveau 2 =annulé=> niveau 1
		def vuInitial()
			reponseNouvelle		= 0
			reponseExistante	= 1
			reponseAnnuler		= 2
		
			@dialogSauvegarder.reset()
			@dialogSauvegarder.add_buttons(
			[$ref[$langue => "nouvelleSauvegarde"], reponseNouvelle],
			[$ref[$langue => "sauvegardeExistante"],reponseExistante],
			[$ref[$langue => "annuler"], reponseAnnuler])
		
			@dialogSauvegarder.show_all
		
			reponse = @dialogSauvegarder.run
			if	reponse == reponseNouvelle
				vuNouvelle()
	
			elsif	reponse == reponseExistante
				vuExistante()
			end
		end
		#:nodoc:
		def vuNouvelle()
			reponseAnnuler		= 0
			reponseAccepter		= 1
			
			@dialogSauvegarder.reset()
			
			@dialogSauvegarder.vbox.pack_start(Label.new($ref[$langue => "nomSauvegarde"]), false, false, 0)
			@dialogSauvegarder.vbox.pack_start(entree = Entry.new()		, false, false, 0)

			@dialogSauvegarder.add_buttons(	[$ref[$langue => "appliquer"], reponseAccepter],
						[$ref[$langue => "annuler"], reponseAnnuler])

			@dialogSauvegarder.show_all		
			if	@dialogSauvegarder.run == reponseAccepter
				@etats[0] ="sauvegarder"
				@etats[1] = @cheminFichierSauvegarde+entree.text()
				notifierObservateurs()
			else
				vuInitial()
			end
		end
		#:nodoc:
		def vuExistante()
			reponseAnnuler		= 0
			reponseAccepter		= 1
			
			@dialogSauvegarder.reset()
			
			@dialogSauvegarder.vbox.pack_start(fichiers = arbreFichiers(), false, false, 0)
		
			@dialogSauvegarder.add_buttons(	[$ref[$langue => "appliquer"], reponseAccepter],
						[$ref[$langue => "annuler"], reponseAnnuler])

			@dialogSauvegarder.show_all
			if	@dialogSauvegarder.run == reponseAccepter
				sauvegardeSelectionnee	= fichiers.selection.selected
				#Sinon erreur la méthode [] n'existe pas pour la class nil
				if(sauvegardeSelectionnee != nil)
					@etats[0] ="sauvegarder"
					@etats[1] = @cheminFichierSauvegarde+sauvegardeSelectionnee[@indexNom].to_s
					notifierObservateurs()
				end
			else
				vuInitial()
			end
		end
		
		vuInitial()

		@dialogSauvegarder.destroy
	end

	#Action réaliser lors de clic sur un bouton de chargement, affiche une boite de dialogue permettant à l'utilisateur de charger une partie existante
	def onClickCharger
		dialog = Dialog.new($ref[$langue => "charger"], @application,
			Dialog::DESTROY_WITH_PARENT,
			[$ref[$langue => "charger"], Dialog::RESPONSE_ACCEPT],
			[$ref[$langue => "annuler"], Dialog::RESPONSE_CANCEL])
	
		
	        fichiers	= arbreFichiers()
	        dialog.vbox.add(fichiers)
	        dialog.show_all
	        
	        reponse = dialog.run
		if reponse == Dialog::RESPONSE_ACCEPT
			sauvegardeSelectionnee	= fichiers.selection.selected
			#Sinon erreur la méthode [] n'existe pas pour la class nil
			if(sauvegardeSelectionnee != nil)
				@etats[0] = "charger"
				@etats[1] = "./sauvegarde/"+sauvegardeSelectionnee[@indexNom]
				notifierObservateurs()
			end
		end
		
		dialog.destroy
		
		return @application
	end
	
	#Définit et renvoi un arbre TreeView des fichiers de sauvegarde
	#notamment utile pour la chargement et le sauvegarde
	def arbreFichiers()
	#			images, Nom, Taille, Date
		@indexNom	= 0
		@indexTaille	= 1
		@indexDate	= 2
		@indexHeure	= 3
		
		liststore = ListStore.new(String, String, String, String)
		liststore.set_sort_column_id(@indexDate, SORT_DESCENDING)
		Dir.chdir("./sauvegarde")  do
  			Dir.new(".").each{ |file|
  				#					c'est un fichier pas un répertoire
  				if file.to_s !=("..")&& file.to_s !=(".") && File.file?(file) 
					fichier			= liststore.append()
				
					fichier[@indexNom]	= file.to_s
					fichier[@indexTaille]	= File.size(file).to_s
					fichier[@indexDate]	= File.new(file).mtime().strftime "%Y/%m/%d"
					fichier[@indexHeure]	= File.new(file).mtime().strftime "%H:%M:%S"
				end
			}
		end
		
		fichiers = TreeView.new(liststore)
		fichiers.selection.mode = SELECTION_SINGLE

		#Colonne 1 , Image + Nom
		colonne         = TreeViewColumn.new($ref[$langue => "nomSauvegarde"])
		
		renderer        = CellRendererPixbuf.new
		renderer.stock_id = Stock::EDIT
		colonne.pack_start(renderer, false)
		
		renderer        = CellRendererText.new
		colonne.pack_start(renderer, true)
		colonne.add_attribute(renderer, "text", @indexNom)
		colonne.sort_column_id = @indexNom
		colonne.signal_connect('clicked') do |w|
			w.sort_order = 
				w.sort_order == SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING
		end
		
		fichiers.append_column(colonne)
	
		#Colonne 2, date plus récente à la plus ancienne
		renderer	= CellRendererText.new
		colonne		= TreeViewColumn.new(	$ref[$langue => "date"], renderer,
							"text" => @indexDate)
		
		colonne.sort_column_id = @indexDate
		colonne.signal_connect('clicked') do |w|
			w.sort_order = 
				w.sort_order == SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING
		end
		fichiers.append_column(colonne)
		
		#Colonne 3, heure plus récente à la plus ancienne
		renderer	= CellRendererText.new
		colonne		= TreeViewColumn.new(	$ref[$langue => "heure"], renderer,
							"text" => @indexHeure)
		colonne.sort_column_id = @indexHeure
		colonne.signal_connect('clicked') do |w|
			w.sort_order = 
				w.sort_order == SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING
		end
		fichiers.append_column(colonne)
		
		return fichiers
	end
	
	#Action réalisé lors du clic sur le bouton d'inventaire
	def onClickInventaire
		@etats[0]="inventaire"
		notifierObservateurs()	
	end
	
	#Action réalisé lors du clic sur le bouton score
	def onClickScore
		@etats[0]="score"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton des options
	def onClickOptions
		dialog = Dialog.new($ref[$langue => "options"], @application,
			Dialog::DESTROY_WITH_PARENT)
			
		dialog.vbox.add(options = VBox.new)
		dialog.vbox.add(vbox = VBox.new())
		
		# ligne 1 à 3 vide
		vbox.add(HBox.new())
		# reste
		vbox.add(table = VBox.new(true))
		
		@boutonFrancais.removeFromParent
		@boutonAnglais.removeFromParent
		@boutonRaccourcis.removeFromParent
		@boutonAppliquer.removeFromParent
		@boutonAnnuler.removeFromParent
		
		# ligne 4 avec boutons langue 5largeur
		table.add(hboxLangue = HBox.new(true))
		hboxLangue.add(HBox.new())
		hboxLangue.add(HBox.new())
		hboxLangue.add(@boutonFrancais)
		hboxLangue.add(@boutonAnglais)
		hboxLangue.add(HBox.new())
		
		# ligne 5 bouton raccourcis
		table.add(hboxRaccourci = HBox.new(true))
		hboxRaccourci.add(HBox.new())
		hboxRaccourci.add(HBox.new())
		hboxRaccourci.add(HBox.new())
		hboxRaccourci.add(@boutonRaccourcis)
		hboxRaccourci.add(HBox.new())
		
		# ligne 6 bouton appliquer/annuler
		table.add(hboxAccept = HBox.new(true))
		hboxAccept.add(HBox.new())
		hboxAccept.add(HBox.new())
		hboxAccept.add(@boutonAppliquer)
		hboxAccept.add(@boutonAnnuler)
		hboxAccept.add(HBox.new())
		
		@boutonAppliquer.set_focus(true)

		chemin = "./images/boutons/"+$langue+"/options_fond.png"
		style = RcStyle.new()
		style.set_bg_pixmap_name(STATE_NORMAL,chemin)
		dialog.modify_style(style)
		
		dialog.set_size_request(738,344)
		dialog.set_resizable(false)
		dialog.show_all
		# Si on ne fait pas ça un clic sur la croix rouge fait un destroy et donc
		# les boutons à l'intérieur sont destroy, on ne peut plus les récupérer
		dialog.signal_connect("delete-event"){ dialog.hide }
		
		@dialog	= dialog
		reponse = dialog.run
		if(reponse == Dialog::RESPONSE_ACCEPT)
			dialog.hide
			if(@etats[0].to_s == "langue" && @etats[1] != $langue)
				setLangue(@etats[1])
				notifierObservateurs()
			end
		elsif(reponse == Dialog::RESPONSE_CANCEL)
			dialog.hide
		end
		
		return @application
	end
	
	#Action réalisé lors du clic sur le bouton des raccourcis dans les options
	def onClickRaccourcis()
		dialog = Dialog.new($ref[$langue => "raccourcis"],
			@application,
			Dialog::DESTROY_WITH_PARENT,
			[$ref[$langue => "appliquer"], Dialog::RESPONSE_ACCEPT],
			[$ref[$langue => "annuler"], Dialog::RESPONSE_CANCEL])
	
		@listeRaccourcis.each{ |model, path, raccourci|
			raccourci[@indexStock]	= raccourci[@indexBouton].image.stock
			raccourci[@indexPixbuf]	= raccourci[@indexBouton].image.pixbuf
		
		}
		treeview = TreeView.new(@listeRaccourcis)
   		treeview.selection.mode = SELECTION_SINGLE
		treeview.set_rules_hint(true)
    
		#Colonne 1 , Image
		rendererImage	= CellRendererPixbuf.new
		colonneImage	= TreeViewColumn.new(	$ref[$langue => "image"], rendererImage,
							"stock-id"	=> @indexStock,
							"pixbuf"	=> @indexPixbuf)
		treeview.append_column(colonneImage)	
		
		#Colonne 2, Raccourcis
		
		rendererRaccourcis	= CellRendererText.new
		colonneRaccourcis	= TreeViewColumn.new(	$ref[$langue => "raccourcis"],
								rendererRaccourcis,
								"text"	=> @indexRaccourcis )
		treeview.append_column(colonneRaccourcis)
		
		# sauvegarde des changements dans une pile
		pileChangement = []
		
		ancienAppuyer	= nil
		idHandler	= nil
		treeview.signal_connect("row-activated") { |cell,ligne, nouvelle|
			# Trouve l'iterateur
			if (iter = @listeRaccourcis.get_iter(ligne))
				
				# La touche que l'on édite est sauvegardé
				ancienKeyVal	= iter[@indexRaccourcis]
				ancienAppuyer	= [iter, ancienKeyVal]
				# Informe l'utilisateur que cette touche est en cours d'édition
				iter[@indexRaccourcis] = $ref[$langue => "appuieTouche"]
				
				if(idHandler != nil)
					dialog.signal_handler_disconnect(idHandler)
					idHandler = nil
				end
				# Capture d'un clic
				idHandler = dialog.signal_connect("key-press-event") do |w, e|
					nomCle = Gdk::Keyval.to_name(e.keyval)
					pileChangement.push([iter, ancienKeyVal])
					iter[@indexRaccourcis]= nomCle.to_s
					ancienAppuyer = nil
				end
			end
		}
		treeview.signal_connect("cursor-changed"){ |s|
			# Si une touche est en cours d'édition on remet son état avant édition
			if(ancienAppuyer != nil)
				ancienIter	= ancienAppuyer[0]
				ancienKeyVal	= ancienAppuyer[1]
				ancienIter[@indexRaccourcis]	= ancienKeyVal
			end
		}

	        dialog.vbox.add(treeview)
	        dialog.show_all
	        reponse = dialog.run
		if reponse == Dialog::RESPONSE_CANCEL			
			#on annule les changements
			while(!pileChangement.empty?)
				iterKeyVal 	= pileChangement.pop
				iter		= iterKeyVal[0]
				keyVal		= iterKeyVal[1]
				iter[@indexRaccourcis] = keyVal
			end
		end
		# Si une touche est encore en cours d'édition on remet son ancien valeur
		if(ancienAppuyer != nil)
			ancienIter	= ancienAppuyer[0]
			ancienKeyVal	= ancienAppuyer[1]
			ancienIter[@indexRaccourcis]	= ancienKeyVal
		end
		
		# Pour rassurer l'utilisateur que le dernier coup est annulé
		dialog.show_all
		forcerAffichage()
		sleep(0.2)
		
		dialog.destroy
		
		return @application
	end
	
	#Action réalisé lors du clic sur la bouton d'aide
	def onClickAide
		effacerContenu()
			    
		@contenuJeu.add(scrollWindow = ScrolledWindow.new(nil,nil) )
				scrollWindow.add_with_viewport(champTexte = TextView.new())
        champTexte.wrap_mode = TextTag::WRAP_WORD_CHAR
				scrollWindow.set_height_request(500)
		@contenuJeu.add(hboxRetour = HBox.new())
		
		@boutonRetourCarte.removeFromParent
		hboxRetour.pack_start(@boutonRetourCarte, false, false, 0)
		#background et foreground du text
		champTexte.modify_base(STATE_NORMAL, @couleurArrierePlan)
		champTexte.modify_text(STATE_NORMAL, @couleurTexte)
		
		#marge à gauche et à Droit du texte
		margin = 50
		champTexte.set_left_margin(margin)
		champTexte.set_right_margin(margin)
		#texte non editable
		champTexte.set_editable(false)
		
		if File.exist?(@cheminManuel)
			text = String.new
			IO.foreach(@cheminManuel) { |x| 
				text += x
			}
			champTexte.buffer.text = text
		end		
		
		@contenuJeu.show_all
		
		return @application
	end
	
	#Action réalisé lors du clic sur la bouton quitter
	def onClickQuitter
		main_quit
	end
	
	#Action réalisé lors du clic sur la bouton pour passer son tour
	def onClickPasser
		@etats[0]="passer"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur la bouton pour passer se faire soigner contre de l'argent
	def onClickSoigner
		@etats[0]="soigner"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur la bouton pour ramasser les objets présent sur la case du héros de l'utilisateur
	def onClickRamasser
		@etats[0]="ramasser"
		notifierObservateurs()
	end

	#Action réalisé lors du clic sur le bouton de déplacement vers le haut
	def onClickHaut
		@etats[0]="haut"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton de déplacement vers le bas
	def onClickBas
		@etats[0]="bas"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton de déplacement vers la gauche
	def onClickGauche
		@etats[0]="gauche"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton de déplacement vers la Droit
	def onClickDroit
		@etats[0]="droit"
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton utiliser dans l'inventaire
	def onClickUtiliser()
		@etats[0] = "utiliser"
		@etats[1] = @objetSelectionne
		notifierObservateurs()
	end
	
	#Action réalisé lors du clic sur le bouton jeter dans l'inventaire
	def onClickJeter()
		dialog = Dialog.new("",
			@application,
			Dialog::DESTROY_WITH_PARENT)
			
		@boutonAppliquer.removeFromParent
		@boutonAnnuler.removeFromParent
		
		dialog.vbox.add(hbox = HBox.new(true))
		hbox.add(@boutonAppliquer)
		hbox.add(@boutonAnnuler)
		
		dialog.show_all
		dialog.set_resizable(false)
		dialog.show_all
		# Si on ne fait pas ça un clic sur la croix rouge fait un destroy et donc
		# les boutons à l'intérieur sont destroy, on ne peut plus les récupérer
		dialog.signal_connect("delete-event"){ dialog.hide }
		
		@dialog	= dialog
		reponse = dialog.run
		if(reponse == Dialog::RESPONSE_ACCEPT)
			dialog.hide
			@etats[0] = "jeter"
			@etats[1] = @objetSelectionne
			notifierObservateurs()
		elsif(reponse == Dialog::RESPONSE_CANCEL)
			dialog.hide
		end
		
		return @application
	end
	
	#Action réalisé lors du clic sur le bouton retour
	def onClickRetourCarte()
		montrerCarte(@carte)
	end
	
end

# Ajout de méthode à Gtk::Widget
class Gtk::Widget

	#Detache "plus proprement" un widget d'un parent que la methode "unparent" => ne génère pas d'erreur pour la libération de mémoire
	def removeFromParent()
		p = self.parent
		if p != nil
			p.remove(self)
		end
	end
end

# Ajout de méthode à Gtk::Dialog
class Gtk::Dialog
	#Supprime tous les boutons et le contenu de la vbox du dialog
	def reset()
		self.action_area.children().each{ |child|
			self.action_area.remove(child)
		}

		self.vbox.children().each{ |child|
			if child != self.action_area
				self.vbox.remove(child)
			end
		}
	end
end
